
#include "xapp_config.h"

#if USER_CHECK_ENABLED( PROTOCOL_PRIV )

#include "pbif.h"
#include "xapp_record.h"
#include "log.h"

#define LOG(...)





#if 1 // General
static void pbm_negative_response( pbd_err_code_t err_code, pb_tx_array_handle_t cb)
{
    uint8_t payload[2];

    payload[0] = (uint8_t)PBD_COMMAND_NEGATIVE;
    payload[1] = (uint8_t)err_code;

    pb_assemble_tx_data(payload, 2, FLAG_ERROR_RESP, cb); 
}

static void pbm_positive_response(pbd_command_t command, pb_tx_array_handle_t cb)
{
    uint8_t payload[1];

    payload[0] = (uint8_t)command;
    pb_assemble_tx_data(payload, 1, FLAG_ACK, cb); 
}
#endif 


#if PB_COMMAND_APPLICATION_ENABLE // Application 
static void pbm_application_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    int index = 1;
    uint8_t field_len, field_type;
    pbd_err_code_t res = PBD_SUCCESS;

    uint8_t temp[100];
    uint16_t chunk_len = 1;
    uint16_t chunk_remain = 100 - 2;
    uint16_t chunk_size = 100 - 2;
    uint8_t *resp = temp + 1;
    temp[0] = PBD_COMMAND_APPLICATION;

    while (index < p_msg->len)
    {
        field_len = p_msg->p_data[ index + 0]; 
        field_type = p_msg->p_data[ index + 1];

        if( (field_len + index + 1) > p_msg->len ){
            res = PBD_ERR_DATA_SIZE;
            break;
        }

        switch( (pbd_application_key_t)field_type)
        {
            case PBD_APPLICATION_KEY_ALARM_CLOCK_1:
            case PBD_APPLICATION_KEY_ALARM_CLOCK_2:
            case PBD_APPLICATION_KEY_ALARM_CLOCK_3:
            case PBD_APPLICATION_KEY_ALARM_CLOCK_4:
            if( field_len == 1){ //read 
                res = pi_app_read_alarm_clock( field_type - PBD_APPLICATION_KEY_ALARM_CLOCK_1, resp + 2, &chunk_size); 
                if(res == PBD_SUCCESS)
                {
                    resp[0] = chunk_size + 1;
                    resp[1] = field_type;

                    chunk_len += chunk_size + 2; 
                    resp += chunk_size + 2;

                    chunk_remain -= chunk_size + 2;
                    if(chunk_remain > 2)
                    {
                        chunk_size = chunk_remain - 2; 
                    }
                    else
                    {
                        chunk_size = 0;
                    }
                }
            }
            else
            {
                res = pi_app_write_alarm_clock(field_type - PBD_APPLICATION_KEY_ALARM_CLOCK_1, p_msg->p_data + index + 2, field_len - 1); 
            }
            break; 

            case PBD_APPLICATION_KEY_PHYSIC_PERIOD:
            if( field_len == 1 )
            {
                res = pi_app_read_physic_period( resp + 2, &chunk_size );
                if(res == PBD_SUCCESS)
                {
                    resp[0] = chunk_size + 1;
                    resp[1] = field_type;

                    chunk_len += chunk_size + 2; 
                    resp += chunk_size + 2;

                    chunk_remain -= chunk_size + 2;
                    if(chunk_remain > 2)
                    {
                        chunk_size = chunk_remain - 2; 
                    }
                    else
                    {
                        chunk_size = 0;
                    }
                }
            }
            else 
            {
                res = pi_app_write_physic_period( p_msg->p_data + index + 2, field_len - 1 );
            }
            break;

            default:
            res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED; 
            break;  
        }

        index += field_len + 1; 
    }
    
    if( res != PBD_SUCCESS)
    {
        pbm_negative_response( res, cb); 
    }
    else 
    {
        pb_assemble_tx_data( temp, chunk_len, 0, cb ); 
    }

}
#endif // !Application

#if PB_COMMAND_BT_ENABLE // BT Module 
static void pbm_btm_command_consume(pb_msg_t* p_msg, pb_tx_array_handle_t cb)
{
    uint8_t field_len = p_msg->p_data[ 1 ];
    uint8_t field_type = p_msg->p_data[ 2 ];
    uint8_t* pfield_data = p_msg->p_data + 3; 

    pbd_err_code_t ret = PBD_SUCCESS;
    uint8_t data[20];
    uint8_t* resp = data + 1;
    data[0] = PBD_COMMAND_BT_MODULE;
    uint16_t chunk_len = 1;
    uint16_t chunk_remain = 19;
    

    switch( (pbd_btm_key_t)field_type )
    {
        // base operation 
        case PBD_BTM_KEY_POWER_OFF:
        ret = pi_btm_power_off( pfield_data, field_len - 1 ); 
        break;
        case PBD_BTM_KEY_POWER_ON:
        ret = pi_btm_power_on( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_OPEN_BLUETOOTH:
        ret = pi_btm_open_bluetooth( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_CLOSE_BLUETOOTH:
        ret = pi_btm_close_bluetooth( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_OPEN_UART:
        ret = pi_btm_open_uart( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_CLOSE_UART:
        ret = pi_btm_close_uart( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_RESET:
        ret = pi_btm_reset( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_OPEN_BLE:
        ret = pi_btm_open_ble( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_CLOSE_BLE:
        ret = pi_btm_close_ble( pfield_data, field_len - 1 );
        break;
        
        

        // get information
        case PBD_BTM_KEY_GET_INFO:
        ret = pi_btm_get_info( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_GET_VERSION:
        ret = pi_btm_get_version( pfield_data, field_len - 1, resp + 2, &chunk_remain );
        if( ret == PBD_SUCCESS )
        {
            resp[0] = chunk_remain + 1;
            resp[1] = PBD_BTM_KEY_GET_VERSION;
            chunk_len += chunk_remain + 2;
        }
        break;
        case PBD_BTM_KEY_GET_BT_MAC:
        ret = pi_btm_get_bt_mac( pfield_data, field_len - 1, resp + 2, &chunk_remain );
        if( ret == PBD_SUCCESS )
        {
            resp[0] = chunk_remain + 1;
            resp[1] = PBD_BTM_KEY_GET_BT_MAC;
            chunk_len += chunk_remain + 2;
        }
        break;
        case PBD_BTM_KEY_GET_VOL:
        ret = pi_btm_get_vol( pfield_data, field_len - 1, resp + 2, &chunk_remain );
        if( ret == PBD_SUCCESS )
        {
            resp[0] = chunk_remain + 1;
            resp[1] = PBD_BTM_KEY_GET_VOL;
            chunk_len += chunk_remain + 2;
        }
        break;
        case PBD_BTM_KEY_SET_HF_VOL:
        ret = pi_btm_set_hf_vol( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_SET_AD_VOL:
        ret = pi_btm_set_ad_vol( pfield_data, field_len - 1 );
        break;

        // calling 
        case PBD_BTM_KEY_DIALING:
        ret = pi_btm_dialing( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_HANG_UP:
        ret = pi_btm_hangup( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_ANSWER:
        ret = pi_btm_answer( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_REDIALING:
        ret = pi_btm_redialing( pfield_data, field_len - 1 );
        break;

        // phone music 
        case PBD_BTM_KEY_PMUSIC_PLAY:
        ret = pi_btm_phone_music_play( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_PMUSIC_PAUSE:
        ret = pi_btm_phone_music_pause( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_PMUSIC_NEXT_TRACK:
        ret = pi_btm_phone_music_next( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_PMUSIC_PREVIOUS_TRACK:
        ret = pi_btm_phone_music_previous( pfield_data, field_len - 1 );
        break;

        // PBAP
        case PBD_BTM_KEY_PBAP_START:
        ret = pi_btm_pbap_start( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_PBAP_CANCEL:
        ret = pi_btm_pbap_cancel( pfield_data, field_len - 1 );
        break;

        // BT
        case PBD_BTM_KEY_QUERY_STATE:
        ret = pi_btm_query_state( pfield_data, field_len - 1, resp + 2, &chunk_remain );
        if( ret == PBD_SUCCESS )
        {
            resp[0] = chunk_remain + 1;
            resp[1] = PBD_BTM_KEY_QUERY_STATE;
            chunk_len += chunk_remain + 2;
        }
        break;

        case PBD_BTM_KEY_CONNECT_TO:
        ret = pi_btm_connect_to( pfield_data, field_len - 1);
        break;
        case PBD_BTM_KEY_CONNECT_LAST:
        ret = pi_btm_connect_last( pfield_data, field_len - 1);
        break;        
        case PBD_BTM_KEY_BT_DISCONNECT:
        ret = pi_btm_bt_disconnect( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_BT_PAIR:
        ret = pi_btm_bt_pair( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_BT_RESET:
        ret = pi_btm_bt_reset( pfield_data, field_len - 1  );
        break;
        case PBD_BTM_KEY_TOGGLE_BT:
        ret = pi_btm_bt_toggle( pfield_data, field_len - 1  );
        break;

        // MIC 
        case PBD_BTM_KEY_OPEN_MIC_LOOP:
        ret = pi_btm_open_mic_loop( pfield_data, field_len - 1 );
        break;
        case PBD_BTM_KEY_CLOSE_MIC_LOOP:
        ret = pi_btm_close_mic_loop( pfield_data, field_len - 1);
        break;

        default:
        ret = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED; 
        break;
    }
    
    if( ret != PBD_SUCCESS)
    {
        pbm_negative_response( ret, cb); 
    }
    else if( chunk_len > 1 )
    {
        pb_assemble_tx_data( data, chunk_len, 0, cb ); 
    }
    else 
    {
        pbm_positive_response( PBD_COMMAND_BT_MODULE, cb );
    }
}

#endif // !BT Module 

#if PB_COMMAND_CONTROL_ENABLE // Control
static void pbm_control_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{    
    int index = 1;
    uint8_t field_len, field_type;
    pbd_err_code_t res = PBD_SUCCESS;

    uint8_t resp[100];
    uint16_t chunk_len = 1;
    uint16_t chunk_key_len = 100 - 2; 
    uint16_t chunk_remain = 100 - 2 ; 
    uint8_t *pdata = resp + 1;    

    resp[0] = PBD_COMMAND_CONTROL;    

    while (index < p_msg->len )
    {
        field_len   = p_msg->p_data[ index + 0];
        field_type  = p_msg->p_data [ index + 1];

        if( (field_len + index + 1) > p_msg->len){
            res = PBD_ERR_DATA_SIZE;
            break; 
        }

        switch( (pbd_control_key_t)field_type)
        {
            case PBD_CONTROL_KEY_SET_DATETIME:
            res = pi_ctrl_write_datetime( p_msg->p_data + index + 2, field_len - 1);
            break;
            case PBD_CONTROL_KEY_GET_DATETIME:
            if( field_len != 1){
                res = PBD_ERR_INVALID_FORMAT;
            }else{
                res = pi_ctrl_read_datetime( pdata + 2, &chunk_key_len);
            }
            break;
            case PBD_CONTROL_KEY_SET_DAY_OF_WEEK:
            res = pi_ctrl_write_day_of_week( p_msg->p_data + index + 2, field_len - 1);
            break;
            case PBD_CONTROL_KEY_GET_DAY_OF_WEEK:
            if( field_len != 1){
                res = PBD_ERR_INVALID_FORMAT;
            }else{
                res = pi_ctrl_read_day_of_week( pdata + 2, &chunk_key_len);
            }
            break; 
            case PBD_CONTROL_KEY_BATTERY_STATUS:
            res = pi_ctrl_set_battery_notify( p_msg->p_data + index + 2, field_len - 1, pdata + 2, &chunk_key_len);
            break;
            case PBD_CONTROL_KEY_GET_LCD_TIMEON:
            if( field_len == 1)
                res = pi_ctrl_get_lcd_time_on( pdata + 2, &chunk_key_len ); 
            else
                res = PBD_ERR_INVALID_LENGTH;
            break;

            case PBD_CONTROL_KEY_HR_SETUP_MEASURE:
            res = pi_ctrl_write_hrs_setup_measure( p_msg->p_data + index + 2, field_len - 1);
            break;
            case PBD_CONTROL_KEY_BP_SETUP_MEASURE:
            res = pi_ctrl_write_bloodpressure_setup_measure( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_CONTROL_KEY_TEMP_SETUP_MEASURE:
            res = pi_ctrl_write_temperature_setup_measure( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_CONTROL_KEY_SPO2_SETUP_MEASURE:
            res= pi_ctrl_write_bloodoxygen_setup_measure( p_msg->p_data + index + 2, field_len - 1 );
            break;
            // case PBD_CONTROL_KEY_HR_RESULT:
            // res = pi_ctrl_write_stop_measure( pdata + 2, field_len - 1); 
            // break;


            case PBD_CONTROL_KEY_INCOMING_CALL:
            res = pi_ctrl_get_add_incoming_call( p_msg->p_data + index + 2, field_len - 1);
            break;
            case PBD_CONTROL_KEY_INCOMING_CALL_REMOVE:
            res = pi_ctrl_get_remove_incoming_call( p_msg->p_data + index + 2, field_len - 1); 
            break;
            //case PBD_CONTROL_KEY_INCOMING_CALL_HANDLE: //device to host 
            //break; 
            case PBD_CONTROL_KEY_MISSED_CALL:
            res = pi_ctrl_get_add_missed_call( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_CONTROL_KEY_NOTIFICATION_APP:
            res = pi_ctrl_set_message_type( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_CONTROL_KEY_NOTIFICATION_DATE:
            res = pi_ctrl_set_message_date( p_msg->p_data + index + 2, field_len - 1); 
            break; 

            case PBD_CONTROL_KEY_NOTIFICATION_TITLE:
            res = pi_ctrl_set_message_title( p_msg->p_data + index + 2, field_len - 1);
            break; 
            case PBD_CONTROL_KEY_NOTIFICATION_MESSAGE:
            res = pi_ctrl_set_message_content( p_msg->p_data + index + 2, field_len - 1); 
            break; 
            case PBD_CONTROL_KEY_NOTIFICATION_MESSAGE_SEGMENT:
            res = pi_ctrl_set_message_content_segment( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_CONTROL_KEY_CAMERA:
            res = pi_ctrl_set_camera( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_CONTROL_KEY_MUSIC:
            res = pi_ctrl_set_music( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_CONTROL_KEY_FINDME:
            res  = pi_ctrl_set_findme( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_CONTROL_KEY_WEAR_DET:
            res = pi_ctrl_set_wear_det( p_msg->p_data + index + 2, field_len - 1);
            break;

            case PBD_CONTROL_KEY_EMS_OP:
            res = pi_ctrl_ems_set( p_msg->p_data + index + 2, field_len - 1 );
            break;
            case PBD_CONTROL_KEY_HEAT_OP:
            res = pi_ctrl_heat_set( p_msg->p_data + index + 2, field_len - 1 );
            break;
            case PBD_CONTROL_KEY_STATUS_OF_EMS:
            res = pi_ctrl_ems_req( p_msg->p_data + index + 2, field_len - 1, pdata + 2, &chunk_key_len );
            break;

            default:
            res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED; 
            break;
        }

        if( res != PBD_SUCCESS ){
            break;
        }

        if( chunk_key_len != chunk_remain )
        {
            pdata[0] = chunk_key_len + 1;
            pdata[1] = field_type;
            pdata += chunk_key_len + 2; 

            chunk_len += chunk_key_len + 2; 
            chunk_remain -= chunk_key_len - 2;
            chunk_key_len = chunk_remain;            
        }
        index += field_len + 1; 
    }
    
    if( res != PBD_SUCCESS )
    {
        pbm_negative_response( res, cb); 
    }
    else
    {
        pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }
}
#endif // !Control

#if PB_COMMAND_OTA_ENABLE // OTA(DFU)
static void pbm_dfu_command_init_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_init( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
static void pbm_dfu_command_write_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_write( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
static void pbm_dfu_command_execute_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_execute( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
static void pbm_dfu_command_query_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_query( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
static void pbm_dfu_command_reset_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_reset( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }    
}
static void pbm_dfu_command_mtu_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_query_mtu( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
static void pbm_dfu_command_version_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t resp[20];
    uint16_t chunk_len; 
    pbd_err_code_t ret_val = pi_dfu_version_req( p_msg->p_data + 1, p_msg->len - 1, resp, &chunk_len);
    if( ret_val == PBD_SUCCESS){
        if( chunk_len > 0)
            pb_assemble_tx_data( resp, chunk_len, 0, cb);
    }else{
        pb_assemble_tx_data( resp, chunk_len, FLAG_ERROR_RESP, cb);
    }
}
#endif // !OTA(DFU)


#if PB_COMMAND_DOWNLOAD_ENABLE // DOWNLOAD
static void pbm_download_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{  
/*    
    // set data write flash 
    uint32_t address = uint32_decode( p_msg->p_data + 1);
    uint8_t *pdata = p_msg->p_data + 5;
    uint16_t size = p_msg->len - 5;
    
    // write to flash 
    
    uint8_t resp[5];
    resp[0] = PBD_COMMAND_DOWNLOAD;
    uint32_encode( address, resp + 1 );
    
    pb_assemble_tx_data( resp, 5, 0, cb ); 
*/

}
#endif // !PB_COMMAND_DOWNLOAD_ENABLE

#if PB_COMMAND_UPLOAD_ENABLE 
static void pbm_upload_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb )
{
    uint32_t address = uint32_decode( p_msg->p_data + 1 ); 
    uint16_t size = uint16_decode( p_msg->p_data + 5 );
    
    uint8_t data[256 + 1 + 4];
    if( size > 256 ) 
    {
        pbm_negative_response( PBD_ERR_DATA_SIZE, cb );
        return;
    }
    
//    iqw_module_spi_flash_release_from_power_off_mode();
//    if( iqw_module_spi_flash_has_task() > 0 )
//    {
//        iqw_module_spi_flash_enter_deep_power_off_mode();
//        pbm_negative_response( PBD_ERR_BUSY, cb );
//        return;
//    }
    
    data[0] = PBD_COMMAND_UPLOAD;
    data[1] = (uint8_t)( address >> 0 );
    data[2] = (uint8_t)( address >> 8 );
    data[3] = (uint8_t)( address >> 16 ); 
    data[4] = (uint8_t)( address >> 24 );
    
//    iqw_module_spi_flash_read_data( address, data + 5, size );
    pb_assemble_tx_data( data, size + 5, 0, cb ); 
//    iqw_module_spi_flash_enter_deep_power_off_mode();
}
#endif // !PB_COMMAND_UPLOAD_ENABLE

#if PB_COMMAND_FACTORY_TEST_ENABLE // Factory test
static void pb_factory_test_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    int index = 1;
    pbd_err_code_t res = PBD_SUCCESS;

    uint8_t resp[30];
    uint16_t chunk_len = 1; 
    uint16_t chunk_remain = 20;
    uint16_t chunk_key_len = 20;
    uint8_t *pdata = resp + 1; 

    uint8_t field_len, field_type;

    resp[0] = PBD_COMMAND_FACTORY_TEST;

    while( index < p_msg->len )
    {
        field_len   = p_msg->p_data[ index + 0];
        field_type  = p_msg->p_data[ index + 1];

        if( (field_len + index + 1) > p_msg->len){
            res = PBD_ERR_DATA_SIZE;
            break; 
        }

        switch( (pbd_factory_test_key_t)field_type)
        {
            case PBD_FACTORY_KEY_ENTER:
            res = pi_ft_start_session( p_msg->p_data + index + 2, field_len - 1); 
            break;
            case PBD_FACTORY_KEY_EXIT:
            res = pi_ft_stop_session( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_FACTORY_KEY_VIBRATE:
            res = pi_ft_set_vibrate( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_FACTORY_KEY_HEARTRATE:
            res = pi_ft_set_heartrate( p_msg->p_data + index + 2, field_len - 1); 
            break; 

            case PBD_FACTORY_KEY_LCD_CALIBRATE:
            res = pi_ft_set_lcd_calibrate( p_msg->p_data + index + 2, field_len - 1); 
            break;

            case PBD_FACTORY_KEY_ALERT:
            res = pi_ft_set_alert( p_msg->p_data + index + 2, field_len - 1); 
            break; 
            case PBD_FACTORY_KEY_TEXT:
            res = pi_ft_set_text( p_msg->p_data + index + 2, field_len - 1); 
            break; 

            case PBD_FACTORY_KEY_SELFTEST_QUERY_STATE:
            res = pi_ft_query_selftest_state( p_msg->p_data + index + 2, field_len - 1, pdata + 2, &chunk_key_len);
            break;

            case PBD_FACTORY_KEY_SELFTEST_QUERY_RESULT:
            res = pi_ft_query_selftest_result( p_msg->p_data + index + 2, field_len - 1, pdata + 2, &chunk_key_len);
            break;

            default:
            res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED; 
            break; 
        }

        if( res != PBD_SUCCESS){
            break; 
        }
        if( chunk_key_len != chunk_remain )
        {
            pdata[0] = chunk_key_len + 1;
            pdata[1] = field_type;
            pdata += chunk_key_len + 2; 

            chunk_len += chunk_key_len + 2; 
            chunk_remain -= chunk_key_len - 2;
            chunk_key_len = chunk_remain;            
        }

        index += field_len + 1; 
    }

    if( res != PBD_SUCCESS)
    {
        pbm_negative_response( res, cb);
    }
    else 
    {
        pb_assemble_tx_data( resp, chunk_len, 0, cb); 
    }
}

#endif // !PB_COMMAND_FACTORY_TEST_ENABLE

#if PB_COMMAND_MEMORY_ENABLE // Memory
static void pbm_memory_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
//    int index = 1;
    pb_err_code_t res = PBD_SUCCESS;
    uint8_t resp[280] = {PBD_COMMAND_MEMORY};
    uint16_t chunk_len = 1;
    uint16_t chunk_remain = 200 - 3;

    uint8_t field_len = p_msg->p_data[1];
    uint8_t field_type = p_msg->p_data[2];
    if( (field_len + 2) != p_msg->len)
        return;

    switch( (pbd_memory_key_t)field_type)
    {
        case PBD_MEMORY_KEY_WRITE_INNER:
        res = pi_mem_write_flash_data( p_msg->p_data + 3, field_len - 1); 
        break; 
        case PBD_MEMORY_KEY_READ_INNER:
        pi_mem_read_flash_data( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        resp[chunk_len + 0] = chunk_remain + 1;
        resp[chunk_len + 1] = PBD_MEMORY_KEY_READ_INNER;
        chunk_len += chunk_remain + 2;
        break; 

#if 1 // SPI FLASH, it should be closed while production      
        case PBD_MEMORY_KEY_EXT_FLASH_READ_DEV_ID:
        pi_mem_ext_flash_read_jedec_id( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        // pi_mem_ext_flash_read_device_id( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_len);
        resp[chunk_len + 0] = chunk_remain + 1;
        resp[chunk_len + 1] = PBD_MEMORY_KEY_EXT_FLASH_READ_DEV_ID;
        chunk_len += chunk_remain + 2;
        break; 
        case PBD_MEMORY_KEY_EXT_FLASH_READ_JEDEC_ID:
        pi_mem_ext_flash_read_jedec_id( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        resp[chunk_len + 0] = chunk_remain + 1;
        resp[chunk_len + 1] = PBD_MEMORY_KEY_EXT_FLASH_READ_JEDEC_ID;
        chunk_len += chunk_remain + 2;
        break; 
        case PBD_MEMORY_KEY_EXT_FLASH_READ_DATA:
        pi_mem_ext_flash_read_data( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        resp[chunk_len + 0] = chunk_remain + 1;
        resp[chunk_len + 1] = PBD_MEMORY_KEY_EXT_FLASH_READ_DATA;
        chunk_len += chunk_remain + 2;
        break; 
        case PBD_MEMORY_KEY_EXT_FLASH_WRITE_DATA:
        res = pi_mem_ext_flash_program_data( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_MEMORY_KEY_EXT_FLASH_ERASE_BLOCK:
        break; 
        case PBD_MEMORY_KEY_EXT_FLASH_ERASE_SECTOR:
        break; 

#endif 

#if 1 // Accelerator 
        case PBD_MEMORY_KEY_ACCEL_READ_REG:
        pi_mem_accel_read_reg( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        resp[ chunk_len + 0] = chunk_remain + 1;
        resp[ chunk_len + 1] = PBD_MEMORY_KEY_ACCEL_READ_REG;
        chunk_len += chunk_remain + 2;
        break; 
        case PBD_MEMORY_KEY_ACCEL_FIFO_DATA:
        pi_mem_accel_set_fifo_notify( p_msg->p_data + 3, field_len - 1 ); 
        break;
#endif 

#if 1 // Ecg 
        case PBD_MEMORY_KEY_ECG_READ_REG:
        pi_mem_ecg_read_reg( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, &chunk_remain);
        resp[ chunk_len + 0] = chunk_remain + 1;
        resp[ chunk_len + 1] = PBD_MEMORY_KEY_ECG_READ_REG;
        chunk_len += chunk_remain + 2;
        break; 
        case PBD_MEMORY_KEY_ECG_FIFO_DATA:
        pi_mem_ecg_set_task( p_msg->p_data + 3, field_len - 1 ); 
        break;
#endif 
        
        case PBD_MEMORY_KEY_TP_DATA:
        res = pi_mem_tp_data_write_notify( p_msg->p_data + 3, field_len - 1); 
        break; 
        
        case PBD_MEMORY_KEY_I2C_READ_DATA:
        res = pi_mem_i2c_read_data( p_msg->p_data + 3, field_len - 1, resp + chunk_len + 2, & chunk_remain );
        resp[ chunk_len + 0] = chunk_remain + 1;
        resp[ chunk_len + 1] = PBD_MEMORY_KEY_I2C_READ_DATA;
        chunk_len += chunk_remain + 2; 
        break;

        case PBD_MEMORY_KEY_I2C_WRITE_DATA:
        res = pi_mem_i2c_write_data( p_msg->p_data + 3, field_len - 1 );
        break;
        
        default:
        res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED;
        break; 


    }
    if( res != PBD_SUCCESS){
        pbm_negative_response( res, cb); 
    }    
    else{
        if(chunk_len > 1){
            pb_assemble_tx_data( resp, chunk_len, 0, cb); 
        }
        else
        {
            pbm_positive_response( PBD_COMMAND_MEMORY, cb);
        }
        
    }
}
#endif // !PB_COMMAND_MEMORY_ENABLE

#if PB_COMMAND_PROFILE_ENABLE // Profile 
static void pbm_profile_read_consume(uint8_t *p_key_list, uint8_t size, pb_tx_array_handle_t cb)
{
    uint32_t index = 0;
    uint8_t temp[200] ; 
    uint8_t * resp = temp + 1;
    uint16_t chunk_len = 0;

    
    uint16_t chunk_remain = 200;     
    uint16_t chunk_size = chunk_remain - 2;
    pbd_err_code_t res = PBD_SUCCESS; 
    uint8_t field_type; 

    temp[0] = PBD_COMMAND_PROFILE;
    chunk_len = 1;

    while (index < size)
    {
        field_type = p_key_list[index];
        switch ((pbd_profile_key_t)field_type)
        {
#if 1 // readonly            
            case PBD_PROFILE_KEY_SYS_INFO:
            res = pi_conf_get_dev_information(resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_FIRMWARE_VERSION:
            res = pi_conf_get_dev_firmware_version(resp + 2, &chunk_size); 
            break;
            case PBD_PROFILE_KEY_PROJECT_CODE:
            res = pi_conf_get_dev_project_code( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_MAC:
            res = pi_conf_get_dev_mac( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_DEVICE_ID:
            res = pi_conf_get_dev_id( resp + 2, &chunk_size); 
            break;
            case PBD_PROFILE_KEY_MTU:
            res = pi_conf_get_mtu( resp + 2, &chunk_size);
            break; 
            case PBD_PROFILE_KEY_SERIAL_NO:
            res = pi_conf_get_serial_no(resp + 2, &chunk_size );
            break;
            case PBD_PROFILE_KEY_LOGO:
            res = pi_conf_get_logo( resp + 2, &chunk_size );
            break;
#endif            

#if 1 // base information
            case PBD_PROFILE_KEY_GENDER:
            res = pi_conf_get_user_gender( resp + 2, &chunk_size); 
            break;
            case PBD_PROFILE_KEY_AGE:
            res = pi_conf_get_user_age( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_HEIGHT:
            res = pi_conf_get_user_height( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_WEIGHT:
            res = pi_conf_get_user_weight( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_SKIN:
            res = pi_conf_get_user_skin( resp + 2, &chunk_size );
            break;
#endif

#if 1 // function 
            case PBD_PROFILE_KEY_FATIGUE_REMINDER:
            res = pi_conf_get_fatigue_reminder( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_DO_NOT_DISTURB:
            res = pi_conf_get_do_not_disturb( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_TARGET_OF_DAY:
            res = pi_conf_get_target_of_day( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_TARGET_OF_WEEK:
            res = pi_conf_get_target_of_week( resp + 2, &chunk_size);
            break;

            case PBD_PROFILE_KEY_PROXIMITY_ALERT:
            res = pi_conf_get_proximity( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_NOTIFICATION_CATEGORY:
            res = pi_conf_get_notification_category( resp + 2, &chunk_size);
            break;
            case PBD_RPOFILE_KEY_NOTIFICATION_APPLICATION:
            res = pi_conf_get_notification_application( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_HERATRATE:
            res = pi_conf_get_heartrate_setting(resp + 2, &chunk_size); 
            break;
            case PBD_PROFILE_KEY_BLOODPRESSURE:
            res = pi_conf_get_bloodpressure_setting(resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_TEMPERATURE:
            res = pi_conf_get_temperature_setting(resp + 2, &chunk_size); 
            break; 
			case PBD_PROFILE_KEY_SLEEP_OPTION:
            res = pi_conf_get_sleep_option( resp + 2, &chunk_size );
            break;
#endif
            case PBD_PROFILE_KEY_BT_SETTING:
            res = pi_conf_get_bt_setting( resp + 2, &chunk_size );
            break;

#if 1 // system 
            case PBD_PROFILE_KEY_LANGUAGE:
            res = pi_conf_get_system_language( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_TIME_FORMAT:
            res = pi_conf_get_system_time_format( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_UNIT:
            res = pi_conf_get_system_unit( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_SMART_LIGHT_ON:
            res = pi_conf_get_system_smart_light_on( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_TIME_OF_LIGHT_ON:
            res = pi_conf_get_system_time_of_light_on( resp + 2, &chunk_size);
            break;
            case PBD_PROFILE_KEY_BRIGHTNESS:
            res = pi_conf_get_system_brightness( resp + 2, &chunk_size);
            break; 
            case PBD_PROFILE_KEY_WEARING_HABIT:
            res = pi_conf_get_system_wearing_habit( resp + 2, &chunk_size);
            break; 
            case PBD_PROFILE_KEY_WATCHFACE:
            res = pi_conf_get_system_watchface( resp + 2, &chunk_size ); 
            break; 
#endif 
            default:
            res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED;
            break;
        }

        if( res == PBD_SUCCESS)
        {
            // len - key assign data 
            resp[0] = chunk_size + 1;
            resp[1] = field_type ;

            // pointer add offset 
            resp += chunk_size + 2;
            chunk_len += chunk_size + 2;

            // calculate 
            chunk_remain -= chunk_size + 2;
            if(chunk_remain > 2){
                chunk_size = chunk_remain - 2 ; 
            }else {
                break; // jump out, no enough buffer to storage read data 
            }
            index ++; 
        }
        else 
        {
            break; 
        }
    }

    if(res > 0)
    {
        //LOG("negative response %x\n", res);
        pbm_negative_response(res, cb); 
    }
    else
    {
        //LOG("response with read data\n");
        pb_assemble_tx_data( temp, chunk_len, 0, cb); 
    }
    
}

static void pbm_profile_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    pbd_err_code_t res = PBD_SUCCESS;

    uint32_t index = 1;
    uint8_t field_len, field_type;

    uint8_t *payload = p_msg->p_data; 

    while (index < p_msg->len)
    {
        // load field lenght & type 
        field_len = payload[index + 0];
        field_type = payload[index + 1];

        // LOG("size = %d, len = %d, type = 0x%X\n", p_msg->len, field_len, field_type); 
        // check is length valid? 
        if (
            (field_len + index) > p_msg->len
        ||  field_len == 0         
            ){
                res = PBD_ERR_INVALID_LENGTH;
                break; 
        }
        
        // execute key function by field type 
        switch ((pbd_profile_key_t)field_type)
        {

        case PBD_PROFILE_KEY_SERIAL_NO:
            res = pi_conf_write_serial_no(payload + index + 2, field_len - 1 );
            break;
        case PBD_PROFILE_KEY_LOGO:
            res = pi_conf_write_logo( payload + index + 2, field_len - 1 );
            break;

#if 1 // base information
        case PBD_PROFILE_KEY_GENDER:
            res = pi_conf_write_user_gender(payload + index + 2, field_len - 1);
            break;
        case PBD_PROFILE_KEY_AGE:
            res = pi_conf_write_user_age(payload + index + 2, field_len - 1);
            break;
        case PBD_PROFILE_KEY_HEIGHT:
            res = pi_conf_write_user_height(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_WEIGHT:
            res = pi_conf_write_user_weight( payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_SKIN:
            res = pi_conf_write_user_skin( payload + index + 2, field_len - 1 );
            break;
#endif

#if 1 // function settings
        case PBD_PROFILE_KEY_FATIGUE_REMINDER:
            res = pi_conf_write_fatigue_reminder(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_DO_NOT_DISTURB:
            res = pi_conf_write_do_no_disturb(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_TARGET_OF_DAY:
            res = pi_conf_write_target_of_day(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_TARGET_OF_WEEK:
            res = pi_conf_write_target_of_week(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_PROXIMITY_ALERT:
            res = pi_conf_write_proximity_alert(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_NOTIFICATION_CATEGORY:
            res = pi_conf_write_notification_category(payload + index + 2, field_len - 1); 
            break;
        case PBD_RPOFILE_KEY_NOTIFICATION_APPLICATION:
            res = pi_conf_write_notification_application(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_HERATRATE:
            res = pi_conf_write_heartrate(payload + index + 2, field_len - 1);
            break; 
        case PBD_PROFILE_KEY_BLOODPRESSURE:
            res = pi_conf_write_bloodpressure( payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_TEMPERATURE:
            res = pi_conf_write_temperature( payload + index + 2, field_len - 1); 
            break; 

		case PBD_PROFILE_KEY_SLEEP_OPTION:
            res = pi_conf_write_sleep_option( payload + index + 2, field_len - 1); 
            break;
#endif
        case PBD_PROFILE_KEY_BT_SETTING:
            res = pi_conf_write_bt_setting( payload + index + 2, field_len - 1 );
            break;

#if 1 // system settings
        case PBD_PROFILE_KEY_LANGUAGE:
            res = pi_conf_write_system_language(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_TIME_FORMAT:
            res = pi_conf_write_system_time_format(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_UNIT:
            res = pi_conf_write_system_unit(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_SMART_LIGHT_ON:
            res = pi_conf_write_system_smart_light_on(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_TIME_OF_LIGHT_ON:
            res = pi_conf_write_system_time_of_light_on(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_BRIGHTNESS:
            res = pi_conf_write_system_brightness(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_WEARING_HABIT:
            res = pi_conf_write_system_wearing_habit(payload + index + 2, field_len - 1); 
            break;
        case PBD_PROFILE_KEY_WATCHFACE:
            res = pi_conf_write_system_watchface( payload + index + 2, field_len - 1); 
            break; 
		case PBD_PROFILE_KEY_MOTOR_LEVEL:
            res = pi_conf_write_system_motor_vibrate_level( payload + index + 2, field_len - 1 );
            break;
#endif

#if 1 //
        case PBD_PROFILE_READ:
            LOG("profile read process\n"); 
            pbm_profile_read_consume( payload + index + 2, field_len - 1, cb); 
            return; 
           // break;

        case PBD_PROFILE_SAVE:
            pi_conf_save_profile(); 
            break;
        
#endif
        default:
            res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED;
        break;
        }

        index += field_len + 1;
    }

    if( res > 0){
        pbm_negative_response( res, cb ); 
    }else{
        pbm_positive_response( PBD_COMMAND_PROFILE, cb); 
    }
}

#endif // !PB_COMMAND_PROFILE_ENABLE

#if PB_COMMAND_RECORD_ENABLE // Record
#define PBM_RECORD_BUFF_SIZE    (280)
static void pbm_record_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    uint8_t buff[ PBM_RECORD_BUFF_SIZE ];

    // only process on key per command 
    uint8_t field_len = p_msg->p_data[ 1 ];
    uint8_t field_type = p_msg->p_data[ 2 ]; 
    pbd_err_code_t res = PBD_SUCCESS;
    uint16_t chunk_len = 1;
    uint16_t chunk_remain = PBM_RECORD_BUFF_SIZE - chunk_len - 3; // command, len, type 
    buff[0] = PBD_COMMAND_RECORD;

    switch( (pbd_record_key_t)field_type)
    {
        case PBD_RECORD_KEY_QUERY:
        res = pi_record_query( p_msg->p_data + 3, field_len - 1, buff + chunk_len + 2,  &chunk_remain);
        if(res == PBD_SUCCESS)
        {
            field_type = PBD_RECORD_KEY_RECORD_SIZE; 
        }
        break;
        case PBD_RECORD_KEY_CREATE_SESSION:
        res = pi_record_request_upload( p_msg->p_data + 3, field_len - 1, buff + chunk_len + 2, &chunk_remain);
        if( res == PBD_SUCCESS)
        {
            if( chunk_remain == 0)
            { //only address
                field_type = PBD_RECORD_KEY_STOP_SESSION; 
                chunk_remain = 0; 
                xapp_record_desave_next_addr();
            }
            else
            {
                field_type = PBD_RECORD_KEY_PACKET_UPLOAD; 
            }
        }
        break;
        case PBD_RECORD_KEY_PACKET_ACK:
        xapp_record_desave_next_addr();
        res = pi_record_reception_ack( p_msg->p_data + 3, field_len - 1, buff + chunk_len + 2, &chunk_remain); 
        if( res == PBD_SUCCESS)
        {
            if( chunk_remain == 4)
            { //only address
                field_type = PBD_RECORD_KEY_STOP_SESSION; 
                chunk_remain = 0;
                xapp_record_desave_next_addr();
            }
            else
            {
                field_type = PBD_RECORD_KEY_PACKET_UPLOAD; 
            }
        }
        break;
        case PBD_RECORD_KEY_STOP_SESSION:
        xapp_record_desave_next_addr();
        res = pi_record_stop_session( p_msg->p_data + 3, field_len - 1);
        chunk_remain = 0;
        break;
        default:
        res = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED;
        break;
    } 

    if( res > 0)
    {
        pbm_negative_response( res, cb); 
    }
    else
    {
        if(field_type == PBD_RECORD_KEY_PACKET_UPLOAD)
        {
            buff[chunk_len + 0] = 5;
            buff[chunk_len + 1] = field_type;
        }
        else
        {
            buff[chunk_len + 0] = chunk_remain + 1;
            buff[chunk_len + 1] = field_type;
        }
        

        chunk_len += chunk_remain + 2;
        pb_assemble_tx_data( buff, chunk_len, 0, cb); 
    }

}
#endif // !PB_COMMAND_RECORD_ENABLE

#if PB_COMMAND_SYSTEM_ENABLE // system
static void pbm_system_command_consume(pb_msg_t *p_msg, pb_tx_array_handle_t cb)
{
    // only process on key per command 
    uint8_t field_len = p_msg->p_data[ 1 ];
    uint8_t field_type = p_msg->p_data[ 2 ]; 
    pbd_err_code_t ret = PBD_SUCCESS;

    switch( (pbd_system_key_t)field_type)
    {
        case PBD_SYSTEM_KEY_POWER_OFF:
        ret = pi_system_power_off( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_SYSTEM_KEY_DEVICE_RESET:
        ret = pi_system_device_reset( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_SYSTEM_KEY_ENTER_DFU:
        ret = pi_system_enter_dfu( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_SYSTEM_KEY_ENTER_TPDFU:
        ret = pi_system_enter_tpdfu( p_msg->p_data + 3, field_len - 1);
        break;

        case PBD_SYSTEM_KEY_ENTER_ULP:
        ret = pi_sytem_enter_ulp( p_msg->p_data + 3, field_len - 1); 
        break;

        case PBD_SYSTEM_KEY_FACTORY_RESET:
        ret = pi_system_factory_reset( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_SYSTEM_KEY_REMOVE_HISTORY_DATA:
        ret = pi_system_clear_history_record( p_msg->p_data + 3, field_len - 1);
        break;
        case PBD_SYSTEM_KEY_RESET_PROFILE:
        ret = pi_system_reset_person_profile( p_msg->p_data + 3, field_len - 1);
        break; 

        case PBD_SYSTEM_KEY_MANUAL_MODE:
        ret = pi_system_set_mode( p_msg->p_data + 3, field_len - 1);
        break; 

        default:
        ret = PBD_ERR_SUB_FUNCTION_NOT_SUPPORTED; 
        break; 
    }

    if( ret == PBD_SUCCESS){
        pbm_positive_response( PBD_COMMAND_SYSTEM, cb);
    }else{
        pbm_negative_response( ret, cb); 
    }
}
#endif // !PB_COMMAND_SYSTEM_ENABLE


void pbif_decode_packet(pb_msg_t * p_msg, pb_tx_array_handle_t cb)
{
    switch((pbd_command_t)p_msg->p_data[FIELD_COMMAND_INDEX])
    {
#if PB_COMMAND_OTA_ENABLE // Dfu Command 
        case PBD_COMMAND_DFU_INIT:
        pbm_dfu_command_init_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_WRITE:
        pbm_dfu_command_write_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_EXECUTE:
        pbm_dfu_command_execute_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_QUERY:
        pbm_dfu_command_query_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_RESET:
        pbm_dfu_command_reset_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_MTU:
        pbm_dfu_command_mtu_consume( p_msg, cb);
        break;
        case PBD_COMMAND_DFU_VERSION:
        pbm_dfu_command_version_consume( p_msg, cb);
        break; 
#endif // !Dfu Command 

#if PB_COMMAND_PROFILE_ENABLE
        case PBD_COMMAND_PROFILE: 
        pbm_profile_command_consume( p_msg, cb);
        break; 
#endif // !PB_COMMAND_PROFILE_ENABLE

#if PB_COMMAND_APPLICATION_ENABLE
        case PBD_COMMAND_APPLICATION:
        pbm_application_command_consume( p_msg, cb); 
        break;
#endif // !PB_COMMAND_APPLICATION_ENABLE

#if PB_COMMAND_CONTROL_ENABLE
        case PBD_COMMAND_CONTROL:
        pbm_control_command_consume( p_msg, cb );
        break; 
#endif // !PB_COMMAND_CONTROL_ENABLE

#if PB_COMMAND_MEMORY_ENABLE
        case PBD_COMMAND_MEMORY:
        pbm_memory_command_consume( p_msg, cb );
        break; 
#endif // !PB_COMMAND_MEMORY_ENABLE

#if PB_COMMAND_RECORD_ENABLE
        case PBD_COMMAND_RECORD:
        pbm_record_command_consume( p_msg, cb ); 
        break; 
#endif // !PB_COMMAND_RECORD_ENABLE

#if PB_COMMAND_DOWNLOAD_ENABLE
        case PBD_COMMAND_DOWNLOAD:
        pbm_download_command_consume( p_msg, cb ); 
        break;
#endif // !PB_COMMAND_DOWNLOAD_ENABLE

#if PB_COMMAND_UPLOAD_ENABLE
        case PBD_COMMAND_UPLOAD:
        pbm_upload_command_consume( p_msg, cb ); 
        break;
#endif // !PB_COMMAND_UPLOAD_ENABLE

#if PB_COMMAND_BT_ENABLE
        case PBD_COMMAND_BT_MODULE:
        pbm_btm_command_consume( p_msg, cb );
        break;
#endif // !PB_COMMAND_BT_ENABLE

#if PB_COMMAND_SYSTEM_ENABLE
        case PBD_COMMAND_SYSTEM:
        pbm_system_command_consume( p_msg, cb); 
        break; 
#endif // !PB_COMMAND_SYSTEM_ENABLE

#if PB_COMMAND_FACTORY_TEST_ENABLE
        case PBD_COMMAND_FACTORY_TEST:
        pb_factory_test_command_consume( p_msg, cb);
        break; 
#endif // !PB_COMMAND_FACTORY_TEST_ENABLE
        
        default:
        break;
    }
    
    pb_message_abort( p_msg ); 
}


#endif // !#if USER_CHECK_ENABLED( PROTOCOL_PRIV )
